package com.rex.saas.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rex.saas.bean.*;
import com.rex.saas.bean.request.AddStrategyTaskRequest;
import com.rex.saas.bean.request.TaskRecordPageRequest;
import com.rex.saas.bean.response.StrategyTaskResponse;
import com.rex.saas.db.entity.SaasDeviceGroupRelation;
import com.rex.saas.db.entity.SaasStrategyTask;
import com.rex.saas.db.entity.SaasStrategyTaskRecord;
import com.rex.saas.db.entity.SaasStrategyTaskRecordDetails;
import com.rex.saas.enums.ConditionTypeEnum;
import com.rex.saas.enums.StrategyTypeEnum;
import com.rex.saas.service.StrategyTaskService;
import com.rex.saas.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/strategy")
public class StrategyController extends BaseController{

    @Autowired
    private StrategyTaskService strategyTaskService;

    @RequestMapping("/types")
    public BaseResponse getTypes(@RequestParam String type) {
        log.info("getTypes =======================================> type:{}", type);
        if (type.equals("airCon")){
            return BaseResponse.ok(strategyTaskService.getAiConRuleType());
        }else if (type.equals("light")){
            return BaseResponse.ok(strategyTaskService.getLightRuleType());
        }else {
            return BaseResponse.error("参数错误", ResultCode.PARAM_ERROR);
        }
    }

    @PostMapping("/records")
    @ResponseBody
    public BaseResponse records(HttpServletRequest request, @RequestBody TaskRecordPageRequest taskRecordPageRequest) {
        log.info("records taskRecordPageRequest:{}",taskRecordPageRequest);
        if (taskRecordPageRequest==null){
            log.error("records taskRecordPageRequest is null");
            return BaseResponse.error("参数错误", ResultCode.PARAM_ERROR);
        }
        BaseResponse checkedResult = checkStrategyTask(request, taskRecordPageRequest.getTaskId());
        if(checkedResult.getCode()!=200){
            return checkedResult;
        }
        Page<SaasStrategyTaskRecord> page = strategyTaskService.queryTaskRecordPage(taskRecordPageRequest);

        Page<StrategyTaskRecord> result = new Page();
        BeanUtils.copyProperties(page, result);
        List<StrategyTaskRecord> records = new ArrayList<>();
        for (SaasStrategyTaskRecord record : page.getRecords()){
            StrategyTaskRecord strategyTaskRecord = new StrategyTaskRecord();
            BeanUtils.copyProperties(record, strategyTaskRecord);
            strategyTaskRecord.setScheduleTime(record.getScheduleTime().getTime());
            records.add(strategyTaskRecord);
        }
        result.setRecords(records);
        return BaseResponse.ok(result);
    }

    @GetMapping("/record/detail")
    @ResponseBody
    public BaseResponse recordDetail(HttpServletRequest request, @RequestParam Long recordId, @RequestParam Long spaceId) {
        log.info("recordDetail recordId:{}",recordId);
        SaasStrategyTaskRecord record = strategyTaskService.getRecordById(recordId);
        if(record==null){
            log.error("recordDetail queryById saasStrategyTaskRecord is null, recordId:{}",recordId);
            return BaseResponse.error("记录不存在", ResultCode.PARAM_ERROR);
        }
        if(!record.getTenantId().equals(JwtUtils.getTenantId(request.getHeader("token")))){
            log.error("recordDetail tenantId not match, record:{}", record);
            return BaseResponse.error("非法记录", ResultCode.PARAM_ERROR);
        }
        List<StrategyTaskRecordDetails> details = new ArrayList<>();
        List<SaasStrategyTaskRecordDetails> strategyTaskRecordDetails = strategyTaskService.queryTaskRecordDetails(recordId);
        for (SaasStrategyTaskRecordDetails detailsRecord : strategyTaskRecordDetails){
            StrategyTaskRecordDetails strategyTaskRecordDetail = new StrategyTaskRecordDetails();
            BeanUtils.copyProperties(detailsRecord, strategyTaskRecordDetail);
            strategyTaskRecordDetail.setAckTime(detailsRecord.getAckTime().getTime());
            strategyTaskRecordDetail.setGmtCreated(detailsRecord.getGmtCreated().getTime());
            String position = spaceService.getPositionInfo(spaceId, detailsRecord.getDeviceName());
            strategyTaskRecordDetail.setPosition(position);
            details.add(strategyTaskRecordDetail);
        }

        return BaseResponse.ok(details);
    }

    @GetMapping("/stopTask")
    @ResponseBody
    public BaseResponse stopStrategyTask(HttpServletRequest request, @RequestParam Long taskId){
        log.info("stopStrategyTask taskId:{}",taskId);
        BaseResponse checkedResult = checkStrategyTask(request, taskId);
        if(checkedResult.getCode()!=200){
            return checkedResult;
        }
        return BaseResponse.ok(strategyTaskService.stopStrategyTask((SaasStrategyTask) checkedResult.getData()));
    }

    @GetMapping("/startTask")
    @ResponseBody
    public BaseResponse startStrategyTask(HttpServletRequest request, @RequestParam Long taskId){
        log.info("startStrategyTask taskId:{}",taskId);
        BaseResponse checkedResult = checkStrategyTask(request, taskId);
        if(checkedResult.getCode()!=200){
            return checkedResult;
        }
        return BaseResponse.ok(strategyTaskService.startStrategyTask((SaasStrategyTask) checkedResult.getData()));
    }

    @GetMapping("/executeTask")
    @ResponseBody
    public BaseResponse executeStrategyTask(HttpServletRequest request, @RequestParam Long taskId){
        log.info("executeStrategyTask taskId:{}",taskId);
        BaseResponse checkedResult = checkStrategyTask(request, taskId);
        if(checkedResult.getCode()!=200){
            return checkedResult;
        }
        SaasStrategyTask saasStrategyTask = (SaasStrategyTask) checkedResult.getData();
        if(!saasStrategyTask.getType().equals(StrategyTypeEnum.ONE_CLICK.getCode())){
            log.error("executeStrategyTask type error, saasStrategyTask:{}", saasStrategyTask);
            return BaseResponse.error("非一键执行场景", ResultCode.PARAM_ERROR);
        }
        return BaseResponse.ok(strategyTaskService.executeStrategyTask((SaasStrategyTask) checkedResult.getData()));
    }

    private BaseResponse checkStrategyTask(HttpServletRequest request, Long id) {
        String token = request.getHeader("token");
        String tenantId = JwtUtils.getTenantId(token);

        SaasStrategyTask strategyTask = strategyTaskService.queryById(id);
        if(strategyTask==null){
            log.error("deleteStrategyTask queryById saasStrategyTask is null, spaceInfoId:{}",id);
            return BaseResponse.error("任务不存在", ResultCode.PARAM_ERROR);
        }

        if(!strategyTask.getTenantId().equals(tenantId)){
            log.error("deleteStrategyTask tenantId not match, tenantId:{}, saasStrategyTask:{}", tenantId, strategyTask);
            return BaseResponse.error("非法任务", ResultCode.PARAM_ERROR);
        }
        return BaseResponse.ok(strategyTask);
    }

    @GetMapping("/deleteTask")
    @ResponseBody
    public BaseResponse deleteStrategyTask(HttpServletRequest request, @RequestParam Long id){
        log.info("deleteStrategyTask spaceInfoId:{}",id);
        BaseResponse checkedResult = checkStrategyTask(request, id);
        if(checkedResult.getCode()!=200){
            return checkedResult;
        }
        return BaseResponse.ok(strategyTaskService.deleteStrategyTask(id));
    }

    @PostMapping("/add")
    @ResponseBody
    public BaseResponse addStrategyTask(HttpServletRequest request, @RequestBody AddStrategyTaskRequest strategyTaskRequest){
        log.info("addStrategyTask:{}",strategyTaskRequest);
        if(StringUtils.isEmpty(strategyTaskRequest.getName())){
            log.error("addStrategyTask name is null,deviceName:{}", strategyTaskRequest);
            return BaseResponse.error("任务名称不能为空", ResultCode.PARAM_ERROR);
        }
        if(strategyTaskRequest.getSpaceId()==null){
            log.error("addStrategyTask spaceId is null,deviceType:{}", strategyTaskRequest);
            return BaseResponse.error("设备类型不能为空", ResultCode.PARAM_ERROR);
        }
        if(strategyTaskRequest.getType()==null
                || (!strategyTaskRequest.getType().equals(StrategyTypeEnum.TIMER.getCode())
                && !strategyTaskRequest.getType().equals(StrategyTypeEnum.ONE_CLICK.getCode())
                && !strategyTaskRequest.getType().equals(StrategyTypeEnum.LINK.getCode())
        )){
            return BaseResponse.error("任务类型异常", ResultCode.PARAM_ERROR);
        }

        String token = request.getHeader("token");
        String tenantId = JwtUtils.getTenantId(token);
        if(StringUtils.isEmpty(tenantId)){
            log.error("addStrategyTask tenantId is null,spaceInfoId:{}", tenantId);
            return BaseResponse.error("token异常", ResultCode.PARAM_ERROR);
        }

        List<SaasStrategyTask> saasStrategyTasks = strategyTaskService.queryByName(strategyTaskRequest.getName(), tenantId, strategyTaskRequest.getSpaceId());
        if (!CollectionUtils.isEmpty(saasStrategyTasks)){
            log.error("addStrategyTask deviceName repeat, deviceName:{}", strategyTaskRequest.getName());
            return BaseResponse.error("任务名称重复", ResultCode.PARAM_ERROR);
        }
        StrategyTaskAction actions = strategyTaskRequest.getAction();
        if(actions==null){
            log.error("addStrategyTask actions is null, actions:{}", actions);
            return BaseResponse.error("任务动作不能为空", ResultCode.PARAM_ERROR);
        }

        if(actions.getType()==null){
            log.error("addStrategyTask actions type is null, actions:{}", actions);
            return BaseResponse.error("任务动作类型不能为空", ResultCode.PARAM_ERROR);
        }

        List<String> devices = null;
        if(actions.getType()==1){
            devices = spaceService.getDeviceNameList(strategyTaskRequest.getSpaceId());
            if(CollectionUtils.isEmpty(devices)){
                log.error("addStrategyTask getDeviceNameList error, spaceId:{}", strategyTaskRequest.getSpaceId());
                return BaseResponse.error("设备不存在", ResultCode.PARAM_ERROR);
            }
        }else if(actions.getType()==2){
            if (actions.getGroupId()==null){
                log.error("addStrategyTask actions groupId is null, actions:{}", actions);
                return BaseResponse.error("分组不能为空", ResultCode.PARAM_ERROR);
            }
            List<SaasDeviceGroupRelation> devicesRelations = groupService.getDevices(actions.getGroupId());
            if(CollectionUtils.isEmpty(devicesRelations)){
                log.error("addStrategyTask getDevices error, groupId:{}", actions.getGroupId());
                return BaseResponse.error("分组设备不存在", ResultCode.PARAM_ERROR);
            }
            devices = devicesRelations.stream().map(SaasDeviceGroupRelation::getDeviceName).collect(Collectors.toList());
        }else if(actions.getType()==3){
            if (CollectionUtils.isEmpty(actions.getDevices())){
                log.error("addStrategyTask actions devices is null, actions:{}", actions);
                return BaseResponse.error("设备列表不能为空", ResultCode.PARAM_ERROR);
            }
        }else {
            log.error("addStrategyTask actions type error, actions:{}", actions);
            return BaseResponse.error("任务动作类型异常", ResultCode.PARAM_ERROR);
        }
        if (CollectionUtils.isEmpty(devices)){
            log.error("addStrategyTask devices is null, devices:{}", devices);
            return BaseResponse.error("设备列表不能为空", ResultCode.PARAM_ERROR);
        }

        for(String dev : devices){
            String[] tmps = dev.split("_");
            if(tmps.length==2){
                dev = tmps[0];
            }
            DeviceBasicData deviceBasicData = rexolarApiClient.getDeviceByDeviceName(dev, token);
            if(deviceBasicData==null){
                log.error("addStrategyTask getDeviceByDeviceName error, deviceName:{}", dev);
                return BaseResponse.error("设备不存在", ResultCode.PARAM_ERROR);
            }
            deviceMap.put(dev, deviceBasicData);
        }
        StrategyTaskCondition conditions = strategyTaskRequest.getCondition();
        if(conditions==null){
            log.error("addStrategyTask conditions is null, strategyTaskRequest:{}", strategyTaskRequest);
            return BaseResponse.error("任务条件不能为空", ResultCode.PARAM_ERROR);
        }
        if (StringUtils.isEmpty(conditions.getParams())){
            log.error("addStrategyTask conditions params is null, strategyTaskRequest:{}", strategyTaskRequest);
            return BaseResponse.error("任务条件参数不能为空", ResultCode.PARAM_ERROR);
        }
        if (StringUtils.isEmpty(conditions.getType())){
            log.error("addStrategyTask conditions type is null, strategyTaskRequest:{}", strategyTaskRequest);
            return BaseResponse.error("任务条件类型不能为空", ResultCode.PARAM_ERROR);

        }
        if(strategyTaskRequest.getType().equals(StrategyTypeEnum.TIMER.getCode())){
            if(!ConditionTypeEnum.Timer.getCode().equals(conditions.getType())){
                log.error("addStrategyTask TIMER conditions type error, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("定时任务条件类型错误", ResultCode.PARAM_ERROR);
            }
            JSONObject params = JSONObject.parseObject(conditions.getParams());
            if (params.get("cron")==null){
                log.error("addStrategyTask conditions params cron is null, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("定时任务条件参数cron不能为空", ResultCode.PARAM_ERROR);
            }
        }else if(strategyTaskRequest.getType().equals(StrategyTypeEnum.LINK.getCode())){
            if(!ConditionTypeEnum.Property.getCode().equals(conditions.getType()) &&
                    !ConditionTypeEnum.Event.getCode().equals(conditions.getType())){
                log.error("addStrategyTask LINK conditions type error, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("触发任务条件类型错误", ResultCode.PARAM_ERROR);
            }
            JSONObject params = JSONObject.parseObject(conditions.getParams());
            JSONArray devAlias = params.getJSONArray("devAlias");
            if(CollectionUtils.isEmpty(devAlias)){
                log.error("addStrategyTask LINK conditions params devices is null, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("触发任务条件参数设备列表不能为空", ResultCode.PARAM_ERROR);
            }
            for(Object dev : devAlias){
                String[] tmps = dev.toString().split("_");
                if(tmps.length==2){
                    dev = tmps[0];
                }
                DeviceBasicData deviceBasicData = rexolarApiClient.getDeviceByDeviceName(dev.toString(), token);
                if(deviceBasicData==null){
                    log.error("addStrategyTask conditions getDeviceByDeviceName error, deviceName:{}", dev);
                    return BaseResponse.error("条件设备不存在", ResultCode.PARAM_ERROR);
                }
            }
            String property = params.getString("propertyName");
            if(StringUtils.isEmpty(property)){
                log.error("addStrategyTask LINK conditions params property is null, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("触发任务条件参数属性不能为空", ResultCode.PARAM_ERROR);
            }
            String compareType = params.getString("compareType");
            if(StringUtils.isEmpty(compareType)){
                log.error("addStrategyTask LINK conditions params compareType is null, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("触发任务条件参数比较方式不能为空", ResultCode.PARAM_ERROR);
            }
            String compareValue = params.getString("compareValue");
            if(StringUtils.isEmpty(compareValue)){
                log.error("addStrategyTask LINK conditions params compareValue is null, strategyTaskRequest:{}", strategyTaskRequest);
                return BaseResponse.error("触发任务条件参数比较值不能为空", ResultCode.PARAM_ERROR);
            }
        }
        return BaseResponse.ok(strategyTaskService.addStrategyTask(strategyTaskRequest, tenantId));
    }

    @GetMapping("/list")
    @ResponseBody
    public BaseResponse list(HttpServletRequest request, @RequestParam Long spaceId, @RequestParam String typeCode){
        String token = request.getHeader("token");
        BaseResponse spaceRsp = validateSpace(spaceId, token);
        if(!spaceRsp.isSuccess()){
            log.error("list validateSpace error, spaceId:{}", spaceId);
            return BaseResponse.error("空间不存在", ResultCode.PARAM_ERROR);
        }
        List<StrategyTaskResponse> strategyTaskResponses = new ArrayList<>();
        List<SaasStrategyTask> saasStrategyTasks = strategyTaskService.list(spaceId, typeCode);
        saasStrategyTasks.forEach(task->{
            StrategyTaskResponse strategyTaskResponse = new StrategyTaskResponse();
            BeanUtils.copyProperties(task, strategyTaskResponse);
            JSONObject actions = JSONObject.parseObject(task.getActions());
            JSONArray devAlias = actions.getJSONArray("devAlias");

            ActionBean actionBean = new ActionBean();
            actionBean.setParams(actions.getString("params"));
            actionBean.setServiceName(actions.getString("serviceName"));
            List<DeviceNameBean> devices = new ArrayList<>();
            for (Object dev : devAlias){
                DeviceNameBean deviceNameBean = new DeviceNameBean();
                deviceNameBean.setDeviceName(dev.toString());
                String alias = dev.toString();
                deviceNameBean.setDeviceAlias(alias);
                devices.add(deviceNameBean);
            }
            actionBean.setDevices(devices);
            strategyTaskResponse.setAction(actionBean);

            JSONObject recovers = JSONObject.parseObject(task.getRecovers());
            if(recovers!=null && !recovers.isEmpty()){
                JSONArray recoversDevAlias = recovers.getJSONArray("devAlias");
                RecoverBean recoverBean = new RecoverBean();
                recoverBean.setParams(recovers.getString("params"));

                List<DeviceNameBean> recoverDeviceNameBeans = new ArrayList<>();
                for (Object dev : recoversDevAlias){
                    DeviceNameBean deviceNameBean = new DeviceNameBean();
                    deviceNameBean.setDeviceName(dev.toString());
                    String alias = dev.toString();
                    DeviceBasicData deviceBasicData = deviceMap.get(dev.toString());
                    if(deviceBasicData==null){
                        deviceBasicData = rexolarApiClient.getDeviceByDeviceName(dev.toString(), rexolarApiClient.getToken());
                        if(deviceBasicData==null){
                            log.warn("addStrategyTask recoversDevAlias getDeviceByDeviceName not exist, deviceName:{}", dev);
                        }else {
                            deviceMap.put(dev.toString(), deviceBasicData);
                        }
                    }
                    if(deviceBasicData!=null && !StringUtils.isEmpty(deviceBasicData.getLabel())){
                        alias = deviceBasicData.getLabel();
                    }
                    deviceNameBean.setDeviceAlias(alias);
                    recoverDeviceNameBeans.add(deviceNameBean);
                }
                recoverBean.setDevices(recoverDeviceNameBeans);
                strategyTaskResponse.setRecover(recoverBean);
            }

            JSONObject conditions = JSONObject.parseObject(task.getConditions());
            if(conditions!=null && !conditions.isEmpty()){
                ConditionBean conditionBean = new ConditionBean();
                String type = (String) conditions.get("type");
                JSONObject params = (JSONObject) conditions.get("params");
                conditionBean.setType(type);
                conditionBean.setParams(params.toString());
                strategyTaskResponse.setConditions(conditionBean);
            }

            strategyTaskResponses.add(strategyTaskResponse);

        });
        return BaseResponse.ok(strategyTaskResponses);
    }
}
